/* vim: set ts=2 et sw=2 cindent fo=qroca: */

package com.globant.google.mendoza;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.globant.google.mendoza.malbec.transport.NanoHTTPD;
import com.globant.google.mendoza.malbec.transport.Receiver;

import com.globant.google.mendoza.command.MendozaCommandResult;
import com.globant.google.mendoza.command.DefaultResultDecorator;

/** The http transport to remotely access the mendoza server as a client.
 */
public final class MendozaServerTransport {

  /** The class logger.
   */
  private static Log log = LogFactory.getLog(MendozaServerTransport.class);

  /** mendoza exposed by this transport.
   */
  private MendozaServer mendozaServer;

  /** The http server implementation.
   */
  private NanoHTTPD httpServer = null;

  /** Creates a new server transport.
   *
   * @param server The server exposed by this transport. It cannot be
   * null.
   *
   * @param portNumber The port where the server transport (or client) is
   * listening on.
   */
  public MendozaServerTransport(final MendozaServer server,
      final int portNumber) {
    if (server == null) {
      throw new IllegalArgumentException(
          "The mendoza server cannot be null");
    }
    mendozaServer = server;
    httpServer = new NanoHTTPD(portNumber,
        new MendozaServerReceiver(), null, null, null);
  }

  /** Returns the port that the server is listening on.
   *
   * If you select port number 0, the server to use any available port.
   * You can use this function to obtain such port.
   *
   * @return Returns the port number that the server is listening on.
   */
  public int getPort() {
    return httpServer.getPort();
  }

  /** The class that implements the transport receiver interface.
   *
   * This class receives the request data, unmarshalls it and sends forwards
   * the corresponding command to the server.
   */
  private class MendozaServerReceiver implements Receiver {

    /** Called when a message is received. This implementation disptaches to
     * the correct function in the server according to the request.
     *
     * @param uri The url without the parameters.
     *
     * @param method The method used to send the request, usually POST or GET.
     *
     * @param header The headers received.
     *
     * @param params The request parameters in case the request is a POST.
     *
     * @param message The received message.
     *
     * @return Returns the message to send to the client as a response.
     */
    public String receive(final String uri, final String method, final
        Properties header, final Properties params, final String message) {
      if (log.isTraceEnabled()) {
        log.trace("Entering receive('" + uri + "', '" + method + ",' ... , '"
            + message + "')");
      }
      MendozaRequest request = new MendozaRequest(
          uri, method, header, params, message);
      DefaultResultDecorator decorator = new DefaultResultDecorator();
      httpServer.setContentType(DefaultResultDecorator.CONTENT_TYPE);
      MendozaCommandResult commandResult = null;
      String result = "Command '" + uri + "' not found";
      if ("/mendoza/checkout".equals(uri)) {
        commandResult = mendozaServer.checkout(request);
      } else if ("/mendoza/checkout/encoded".equals(uri)) {
        commandResult = mendozaServer.checkoutEncoded(request);
      } else if ("/mendoza/login".equals(uri)) {
        commandResult = mendozaServer.login(request);
      } else if ("/mendoza/reset".equals(uri)) {
        commandResult = mendozaServer.reset(request);
      } else if ("/mendoza/signature".equals(uri)) {
        commandResult = mendozaServer.assertSignature(request);
      } else if ("/mendoza/cart".equals(uri)) {
        commandResult = mendozaServer.assertCart(request);
      } else if ("/mendoza/merchant".equals(uri)) {
        commandResult = mendozaServer.changeMerchant(request);
      } else if ("/mendoza/coupon".equals(uri)) {
        commandResult = mendozaServer.addCoupon(request);
      } else if ("/mendoza/gift".equals(uri)) {
        commandResult = mendozaServer.addGiftCertificate(request);
      } else if ("/mendoza/status".equals(uri)) {
        commandResult = mendozaServer.status(request);
      } else if ("/mendoza/placeorder".equals(uri)) {
        commandResult = mendozaServer.placeOrder(request);
      } else if ("/mendoza/charge".equals(uri)) {
        commandResult = mendozaServer.chargeOrder(request);
      } else if ("/mendoza/cancel".equals(uri)) {
        commandResult = mendozaServer.cancelOrder(request);
      } else if ("/mendoza/refund".equals(uri)) {
        commandResult = mendozaServer.refundOrder(request);
      } else if ("/mendoza/help".equals(uri)) {
        commandResult = mendozaServer.help(request);
        httpServer.setContentType("text/html");
      }

      if (commandResult != null) {
        result = commandResult.decorate(decorator);
      }
      log.trace("Leaving receive");
      return result;
    }

    /** Called when a message has been received and processed.
     *
     * This implementation does nothing.
     *
     * @param message The received message.
     */
    public void received(final String message) {
    }
  }
}

